Option Explicit

'################################################################
' Descriptor
' 单列结构 的 字段信息
'################################################################

Implements ISqlTranslateNameInfo
Implements ISqlTranslateColInfo

'################################################################
' Field
'################################################################
' 表名 token
Private tableNameToken As SqlToken
' 列名 token
Private colNameToken As SqlToken
' 别名 token
Private colAliasNameToken As SqlToken
' 表名 和 列名之间的 [.]
Private pointToken As SqlToken

' 原始列名
Private originColName As String
' 转换后的列名
Private translatedColName As String
' 非要求类型的列名称
Private reverseTypeName As String

' 列所在的原始表名
Private originTableName As String
' 列所在的原始表名的别名
Private tableAliasName As String

'################################################################
' Function
'################################################################
' 清空表名部分的 token 值
Public Sub clearTableNameTokenVal()
    ' 清空表名部分的 token 值
    If Not tableNameToken Is Nothing Then
        tableNameToken.value = ""
    End If

    If Not pointToken Is Nothing Then
        pointToken.value = ""
    End If
End Sub

' 设置 [.] 所在的token
Public Sub setPointToken(ByRef pt As SqlToken)
    Set pointToken = pt
End Sub

' 设置列所在的表的表名 token
' @param tableNameTokenVal 列所在的表的表名 token
Public Sub setTableNameToken(ByRef tableNameTokenVal As SqlToken)
    Set tableNameToken = tableNameTokenVal

    If tableNameToken Is Nothing Then
        originTableName = ""
        tableAliasName = ""
    Else
        originTableName = tableNameToken.value
        tableAliasName = originTableName
    End If
End Sub

' 设置列名的 token
' @param colNameTokenVal 列名的 token
Public Sub setColNameToken(ByRef colNameTokenVal As SqlToken)
    Set colNameToken = colNameTokenVal

    If colNameToken Is Nothing Then
        originColName = ""
        translatedColName = ""
        reverseTypeName = ""
    Else
        originColName = colNameToken.value
        translatedColName = originColName
        reverseTypeName = originColName
    End If
End Sub

'################################################################
' Implements ISqlTranslateColInfo Function
'################################################################
' 获取使用到的原始列名
Public Function ISQLTranslateColInfo_getOriginColName() As String
    ISQLTranslateColInfo_getOriginColName = originColName
End Function

' 设置变换后的列名
Public Sub ISQLTranslateColInfo_setTranslatedColName(ByRef n As String)
    ' 设置表的转换后名称
    translatedColName = n

    ' 然后将转换后名称写入名称 token
    If Not colNameToken Is Nothing Then
        colNameToken.value = n
    End If
End Sub

' 读取后的列名
Public Function ISQLTranslateColInfo_getTranslatedColName() As String
    ISQLTranslateColInfo_getTranslatedColName = translatedColName
End Function

' 获取使用到的原始表名
Public Function ISQLTranslateColInfo_getTableName() As String
    ISQLTranslateColInfo_getTableName = originTableName
End Function

' 设置表所在的的别名
Public Sub ISQLTranslateColInfo_setTableAliasName(ByRef n As String)
    ' 缓存别名
    tableAliasName = n
    ' 将别名写回表名 token 中
    ' （只在sql中声明了列所在的表时进行覆盖）
    If Not tableNameToken Is Nothing Then
        tableNameToken.value = n
    End If
End Sub

' 获取列所在的表的别名
Public Function ISQLTranslateColInfo_getTableAliasName() As String
    ISQLTranslateColInfo_getTableAliasName = tableAliasName
End Function

' 设置当前列的别名 token
Public Sub ISQLTranslateColInfo_setAliasNameToken(ByRef token As SqlToken)
    Set colAliasNameToken = token
End Sub

' 获取当前列的别名
Public Function ISQLTranslateColInfo_getAliasName() As String
    If colAliasNameToken Is Nothing Then
        ISQLTranslateColInfo_getAliasName = ""
    Else
        ISQLTranslateColInfo_getAliasName = colAliasNameToken.value
    End If
End Function

' 翻译列信息
' @param startEnv 搜索表名的起始作用域(当前列所在的 env)
' @param translateType 转换的类型(逻辑->物理=0, 物理->逻辑=1)
Public Sub ISQLTranslateColInfo_translate(ByRef startEnv As ISqlTranslateEnv, ByRef em As ISqlEntityManager, ByVal translateType As Integer)
    ' 1. 列对象中有【表名】
    '     1. 到缓存 `translatedTableNameMap` 中检查【表名】是否存在
    '     2. 如果【表名】不在缓存中 --> 到父作用域中搜索，直到找到一个可用的作用域
    '     3. 如果【表名】存在
    '         1. 如果原始列名不存在，则跳转到 1.3.5
    '         2. 通过 `getTableEnvByName` 从作用域中获取对应的表级作用域对象
    '             - 如果无法获取到，则跳转到 1.3.5
    '         3. 从表级作用域的筛选项中获取对应的列名称信息
    '             - 如果无法获取到，则跳转到 1.3.5
    '         4. 保存转化后名称
    '             - 如果别名非空，则将别名保存为转化后名称
    '             - 否则保存转化后名称
    '         5. 保存非要求名称
    '         6. 替换【表名】为别名
    '             1. 如果 [表名] 已经在别名集合 `tableAliasNameSet` 中了，则不需要替换
    '             2. 如果 [表名] 不在别名集合中，则尝试到缓存 `tableAliasNameMap` 中获取对应的别名
    '                 1. 如果能够找到，则设置别名
    '                 2. 如果无法找到，则检查 env 的配置属性，如果允许清空，则清空表名；否则保留原始表名
    '
    ' 2. 列对象中没有【表名】
    '      如果列名是 `""`， 则停止
    '      否则，到整个作用域下的各个表中进行搜索，如果当前作用域中没有，则到父级作用域中搜索

    Dim targetEnv As ISqlTranslateEnv
    Set targetEnv = startEnv

    Dim ni As ISqlTranslateNameInfo

    If originTableName <> "" Then
        ' 1. 列对象中有【表名】
        While Not targetEnv Is Nothing
            ' 1.1 到缓存 `translatedTableNameMap` 中检查【表名】是否存在
            '     如果存在，则立刻退出
            If targetEnv.isInTranslatedTableNameMap(originTableName) Then
                Goto while1Break
            End If

            ' 1.2 如果【表名】不在缓存中，则到父作用域中搜索
            Set targetEnv = targetEnv.getParentEnv
        Wend
while1Break:

        ' 如果未找到一个可用的作用域，则立刻停止
        If targetEnv Is Nothing Then
            Exit Sub
        End If

        ' 1.3 如果【表名】存在
        ' 1.3.1 如果原始列名不存在，则跳转到 1.3.5
        If originColName <> "" Then
            ' 1.3.2 通过 `getTableEnvByName` 从作用域中获取对应的表级作用域对象
            Dim tableEnv As ISqlTranslateEnv
            Set tableEnv = targetEnv.getTableEnvByName(originTableName)

            If Not tableEnv Is Nothing Then
                ' 1.3.3 从表级作用域的筛选项中获取对应的列名称信息
                Set ni = tableEnv.findColNameInfoInSelectCols(originColName, em, translateType)

                If Not ni Is Nothing Then
                    With ni
                        ' 1.3.4 保存转化后名称
                        If .getAliasName <> "" Then
                            ISQLTranslateColInfo_setTranslatedColName .getAliasName
                        Else
                            ISQLTranslateColInfo_setTranslatedColName .getTranslatedName
                        End If

                        ' 1.3.5 保存非要求名称
                        reverseTypeName = .getReverseTypeName
                    End With
                End If
            End If

            ' 1.3.3.6 替换【表名】为别名
            '     如果 [表名] 不在别名集合中，说明这不是一个别名
            '     则尝试到缓存 `tableAliasNameMap` 中获取对应的别名
            If Not targetEnv.isTableAlias(originTableName) Then
                Dim tableAliasName As String
                tableAliasName = targetEnv.findTableAliasName(originTableName)

                If tableAliasName <> "" Then
                    ISQLTranslateColInfo_setTableAliasName tableAliasName
                Else
                    If startEnv.needClearColTableWhenNoTableAlias Then
                        ' 1.3.6.2.1 如果无法找到，则检查 env 的配置属性.如果允许清空，则清空表名
                        clearTableNameTokenVal
                    Else
                        ' 1.3.6.2.2 否则，搜索表的[转换后名称]
                        Dim tableTranslatedTableName As String
                        tableTranslatedTableName = targetEnv.getTranslatedTableName(originTableName)

                        ' 1. 如果能够搜索到，则将列的表名设置为: 表的[转换后名称]
                        ' 2. 否则，保留原始表名
                        If tableTranslatedTableName <> "" Then
                            ISQLTranslateColInfo_setTableAliasName tableTranslatedTableName
                        End If
                    End If
                End If
            End If
        End If
    Else
        ' 2. 列对象中没有【表名】
        ' 2.1 如果列名是 `""`， 则停止
        If originColName = "" Then
            Exit Sub
        End If

        ' 2.2 到整个作用域下的各个表中进行搜索，如果当前作用域中没有，则到父级作用域中搜索
        Dim pair As ObjPair
        While Not targetEnv Is Nothing
            Set pair = targetEnv.findColNameInfoInTables(originColName, em, translateType)
            If Not pair Is Nothing Then
                Goto findPairBreak
            End If
            Set targetEnv = targetEnv.getParentEnv
        Wend
findPairBreak:

        ' 2.3 如果能够成功搜索到，则缓存名称
        If Not pair Is Nothing Then
            Set ni = pair.Key2

            ' 2.3.1 缓存名称信息中的 [转换后名称]
            ' 如果名称信息中包含别名，则将别名缓存为 [转换后名称]
            With ni
                If .getAliasName <> "" Then
                    ISQLTranslateColInfo_setTranslatedColName .getAliasName
                ElseIf .getTranslatedName <> "" Then
                    ' 2.3.2 如果名称信息中的 [转换后名称] 不是空，则将别名缓存为 [转换后名称]
                    ISQLTranslateColInfo_setTranslatedColName .getTranslatedName
                End If

                ' 2.3.2 缓存名称信息中的 [非要求名称]
                reverseTypeName = .getReverseTypeName
            End With

            ' 2.3.3 保存名称信息所在表的别名
            Dim translatedInfoEnv As SqlTranslateTableEnv
            Set translatedInfoEnv = pair.Key1
            ISQLTranslateColInfo_setTableAliasName translatedInfoEnv.getTableAliasName
        End If

    End If
End Sub

'################################################################
' Implements ISqlTranslateNameInfo Function
'################################################################
' 获取转换后名称
Public Function ISqlTranslateNameInfo_getTranslatedName() As String
    ISqlTranslateNameInfo_getTranslatedName = translatedColName
End Function

' 获取别名
Public Function ISqlTranslateNameInfo_getAliasName() As String
    ISqlTranslateNameInfo_getAliasName = ISQLTranslateColInfo_getAliasName
End Function

' 获取非要求类型的名称
Public Function ISqlTranslateNameInfo_getReverseTypeName() As String
    ISqlTranslateNameInfo_getReverseTypeName = reverseTypeName
End Function

